package org.totoro.memory.jmm;

/**
 * 原子性测试
 * 配合 idea  的 "jclasslib Bytecode viewer" 插件查看反编译的代码
 * <p>
 * 参考：https://app.yinxiang.com/shard/s45/nl/10505682/85aafb3d-d040-45bb-96ef-652408d17e88
 * 参考：jvm 字节码指令
 *
 * @author daocr
 * @date 2020/2/29
 */
public class JmmAtomicity {

    static volatile int num = 0;

//    static int num = 0;

    /**
     * volatile 关键字只能保证内存的可见性，但是不能保证 i++ 的原子性
     * 原因：i++ 其实要经过四个个步骤，第一个步骤读取 i 的值（getstatic），第二步 准备常量1（iconst_1） ，第三步 两个值相加（iadd） 第四步 结果写入内存 （putstatic）
     *
     * @param args
     * @throws InterruptedException
     */
    public static void main(String[] args) throws InterruptedException {


        Thread A = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                num++;
            }
        });

        Thread B = new Thread(() -> {
            for (int i = 0; i < 100000; i++) {
                num++;
            }
        });

        A.start();
        B.start();

        A.join();
        B.join();

        System.out.println("num :" + num);

    }

}

/*

javap -c org.totoro.memory.jmm.JmmAtomicity
Compiled from "JmmAtomicity.java"
public class org.totoro.memory.jmm.JmmAtomicity {
  static int i;

  public org.totoro.memory.jmm.JmmAtomicity();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: getstatic     #2                  // Field i:I 读取数据
       3: iconst_1                          // 将1压入堆栈
       4: iadd                              // 将栈顶两int类型数相加，结果入栈。
       5: putstatic     #2                  // Field i:I 把结果复制给变量
       8: return

  static {};
    Code:
       0: bipush        10
       2: putstatic     #2                  // Field i:I
       5: return
}

* */